/*******************************************************************************
 * 创建: 2025年11月04日
 * 作者: 水煮肉片饭(27185709@qq.com)
 * 描述: 快照
 * 将所有子节点的内容，合成一张图传递给父节点的Sprite
 * 对父节点的Sprite使用Shader，就可以影响所有子节点
 * 如果子节点是动态的，需打开Snapshot的动态刷新
*******************************************************************************/
import { _decorator, clamp, Component, Color, Node, UITransform, NodeEventType, Sprite, isValid, CCObject, CameraComponent, RenderTexture, SpriteFrame } from 'cc';
const { ccclass, property, executeInEditMode, requireComponent, menu } = _decorator;
@ccclass
@executeInEditMode
@requireComponent(Sprite)
@menu('Gi/Shader/Snapshot')
class Snapshot extends Component {
    @property
    _priority: number = 0;
    @property({ displayName: '渲染优先级' })
    get priority() { return this._priority; }
    set priority(val) {
        this._priority = val = clamp(val | 0, 0, 65535);
        this.camera && (this.camera.priority = val);
    }
    @property
    _isRefresh: boolean = false;
    @property({ displayName: '动态刷新' })
    get isRefresh() { return this._isRefresh; }
    set isRefresh(val) {
        this._isRefresh = val;
        this.camera && (this.camera.clearFlags = val ? CameraComponent.ClearFlag.SOLID_COLOR : CameraComponent.ClearFlag.DEPTH_ONLY);
    }
    static layer: number = 26;
    layer: number = 0;
    camera: CameraComponent = null;
    sprite: Sprite = null;
    protected onLoad(): void {
        this.sprite = this.node.getComponent(Sprite);
        this.sprite.material.setProperty('sampleFromRt', 1);
        let ut = this.node.getComponent(UITransform);
        let renderTexture = new RenderTexture();
        renderTexture.initialize({ width: Math.max(ut.width, 1), height: Math.max(ut.height, 1) });
        this.sprite.sizeMode = Sprite.SizeMode.CUSTOM;
        (this.sprite.spriteFrame ||= new SpriteFrame()).texture = renderTexture;
        let cameraNode = this.node.getChildByName('Camera');
        if (!isValid(cameraNode)) {
            cameraNode = new Node('Camera');
            cameraNode.setParent(this.node);
            cameraNode.addComponent(CameraComponent);
            cameraNode._objFlags |= CCObject.Flags.HideInHierarchy;
        }
        this.layer = 1 << Snapshot.layer++;
        let camera = this.camera = cameraNode.getComponent(CameraComponent);
        camera.visibility = this.layer;
        camera.priority = this.priority;
        camera.clearFlags = this._isRefresh ? CameraComponent.ClearFlag.SOLID_COLOR : CameraComponent.ClearFlag.DEPTH_ONLY;
        camera.clearColor = new Color(0, 0, 0, 0);
        camera.near = 0;
        camera.projection = CameraComponent.ProjectionType.ORTHO;
        camera.targetTexture = renderTexture;
        this.updateSize();
        this.node.on(NodeEventType.SIZE_CHANGED, this.updateSize, this);
        this.node.on(NodeEventType.CHILD_ADDED, this.onChildAdded, this);
        this.node.on(NodeEventType.CHILD_REMOVED, this.onChildRemoved, this);
    }
    protected onDestroy(): void {
        this.camera.targetTexture = null;
        this.sprite.spriteFrame.texture.destroy();
        this.node.off(NodeEventType.SIZE_CHANGED, this.updateSize, this);
        this.node.off(NodeEventType.CHILD_ADDED, this.onChildAdded, this);
        this.node.off(NodeEventType.CHILD_REMOVED, this.onChildRemoved, this);
    }
    protected onEnable(): void {
        for (let children = this.node.children, i = children.length - 1; i >= 0; children[i--].layer = this.layer);
    }
    protected onDisable(): void {
        for (let children = this.node.children, i = children.length - 1; i >= 0; children[i--].layer = this.node.layer);
    }
    onChildAdded(child: Node): void {
        child.layer = this.layer;
    }
    onChildRemoved(child: Node): void {
        child.layer = this.node.layer;
    }
    updateSize(): void {
        let ut = this.node.getComponent(UITransform);
        let cw = ut.width * this.node.scale.x, ch = ut.height * this.node.scale.y;
        this.camera.node.setPosition(cw * (0.5 - ut.anchorX), ch * (0.5 - ut.anchorY));
        this.camera.orthoHeight = ch * 0.5;
        this.camera.far = ch;
    }
}
declare global {
    module gi {
        class Snapshot extends Component {
            priority: number;
            isRefresh: boolean;
        }
    }
}
((globalThis as any).gi ||= {}).Snapshot ||= Snapshot;